package com.xiaoyushu.user.biz.runner;

import cn.hutool.core.collection.CollUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.xiaoyushu.framework.common.util.JsonUtils;
import com.xiaoyushu.user.biz.constant.RedisKeyConstants;
import com.xiaoyushu.user.biz.domain.dataobject.PermissionDO;
import com.xiaoyushu.user.biz.domain.dataobject.RoleDO;
import com.xiaoyushu.user.biz.domain.dataobject.RolePermissionRelDO;
import com.xiaoyushu.user.biz.domain.mapper.PermissionDOMapper;
import com.xiaoyushu.user.biz.domain.mapper.RoleDOMapper;
import com.xiaoyushu.user.biz.domain.mapper.RolePermissionRelDOMapper;


import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 推送角色权限数据到Redis中
 */
@Component
@Slf4j
public class PushRolePermissions2RedisRunner implements ApplicationRunner {

    @Resource
    private RedisTemplate<String,String> redisTemplate;

    @Resource
    private RoleDOMapper roleDOMapper;

    @Resource
    private PermissionDOMapper permissionDOMapper;

    @Resource
    private RolePermissionRelDOMapper rolePermissionRelDOMapper;

    //权限同步标记 key
    private static final String PUSH_PERMISSION_FLAG="push.permission.flag";


    @Override
    public void run(ApplicationArguments args) {
        log.info("==> 服务启动，开始同步角色权限数据到 Redis 中...");
        try{
            //是否能够同步数据：原子操作  只有在键值不存在时，才会设置该键值为“1” ，并设置过期时间为1天
            Boolean canPushed = redisTemplate.opsForValue().setIfAbsent(PUSH_PERMISSION_FLAG, "1", 1, TimeUnit.DAYS);

            if (!canPushed){
                log.info("==> 角色权限数据已经同步致redis中，不再同步...");
                return;
            }
            // 查询出所有角色
            List<RoleDO> roleDOList = roleDOMapper.selectEnabledList();


            if (CollUtil.isNotEmpty(roleDOList)){
                //拿到所有角色的 ID
                List<Long> roleIds = roleDOList.stream().map(RoleDO::getId).toList();
                //根据 角色ID ，批量后才想你出所有角色对应的权限
                List<RolePermissionRelDO> rolePermissionRelDOS = rolePermissionRelDOMapper.selectByRoleIds(roleIds);
                //按角色ID 分组，每个角色ID对应多个权限ID
                Map<Long, List<Long>> roleIDPermissionsMap = rolePermissionRelDOS.stream().collect(
                        Collectors.groupingBy(RolePermissionRelDO::getRoleId,
                                Collectors.mapping(RolePermissionRelDO::getPermissionId, Collectors.toList()))
                );
                //查询 APP 端所有被启用 的 权限
                List<PermissionDO> permissionDOS = permissionDOMapper.selectAppEnabledList();
                //按角色 ID分组，每个角色ID 对应多个权限 ID
                Map<Long,PermissionDO> perMissionIdDOMap= permissionDOS.stream().collect(
                        Collectors.toMap(PermissionDO::getId, permissionDO -> permissionDO)
                );

                //组织 角色ID-权限 关系
                Map<String,List<String>> roleKeyPermissionsMap=Maps.newHashMap();

                //虚幻所有角色
                roleDOList.forEach(roleDO -> {
                    //当前角色ID
                    Long roleID = roleDO.getId();

                    //当前角色 roleKey
                    String roleKey = roleDO.getRoleKey();
                    //当前角色 ID 对应的权限ID 集合
                    List<Long> permissionIds = roleIDPermissionsMap.get(roleID);
                    if (CollUtil.isNotEmpty(permissionIds)){
                        List<String> permissionKeys=Lists.newArrayList();
                       // ArrayList<PermissionDO> perDOS = Lists.newArrayList();
                        permissionIds.forEach(permissionId -> {
                            PermissionDO permissionDO = perMissionIdDOMap.get(permissionId);
                            if (permissionDO != null){
                         //       perDOS.add(permissionDO);
                                permissionKeys.add(permissionDO.getPermissionKey());
                            }
                        });
                        roleKeyPermissionsMap.put(roleKey,permissionKeys);
                    }
                });
                //同步到Redis中，方便后续网关查询Redis ,用于鉴权
                roleKeyPermissionsMap.forEach((roleKey,permissionKeys)->{
                    String key = RedisKeyConstants.buildRolePermissionsKey(roleKey);
                    log.info("==> 角色权限数据同步到 Redis 中，roleKey: {}, permissionKeys: {}", roleKey, permissionKeys);
                    redisTemplate.opsForValue().set(key, JsonUtils.toJsonString(permissionKeys));
                });
            }
            log.info("==> 服务启动，成功同步角色权限数据到 Redis 中...");
        }catch (Exception e){
            log.error("==> 服务启动，同步角色权限数据到 Redis 中失败！", e);
        }
    }
}